/*!  \file  Timer.cpp
 *	  \brief  
 * 
 *   \details   details
 *   \author    Yordan Madzhunkov German Research School for Simulation Sciences GmbH
 *   \version   1.0
 *   \date      04/21/2013 12:27:01 PM
 *   \copyright GNU Public License.
 */

#include <time.h>
#include <sys/times.h>
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include "Timer.h"
using namespace std;
Timer * Timer::myInstance = 0;
Timer * Timer::instance() {
	if (!myInstance)
		myInstance = new Timer();
	return myInstance;
}
Timer::Timer() {
	rres = 1.0 / sysconf(_SC_CLK_TCK);
}
double Timer::getUserTime(){   // CPU time spent executing instructions of the calling process.
   struct tms t;
	times(&t);
	return t.tms_utime * rres;
}
double Timer::getSysTime(){    // CPU time spent in the system while executing tasks on behalf of the calling process
   struct tms t;
	times(&t);
	return t.tms_stime * rres;;
}
double Timer::getRealTime(){   // CPU time spent executing instructions of the calling process.
	struct timespec spec;
	clock_gettime(CLOCK_REALTIME, &spec);
	return spec.tv_nsec * 1e-9 + spec.tv_sec;	
}
double Timer::getProcTime(){   // High-resolution per-process timer from the CPU.
	struct timespec spec;
	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec);
	return spec.tv_nsec * 1e-9 + spec.tv_sec;	
}
double Timer::getMonoTime() {   // Clock that cannot be set and represents monotonic time since some unspecified starting point.
	struct timespec spec;
	clock_gettime(CLOCK_MONOTONIC, &spec);	
	return spec.tv_nsec * 1e-9 + spec.tv_sec;	
}
double Timer::getThreadTime(){ // Thread-specific CPU-time clock.
	struct timespec spec;
	clock_gettime(CLOCK_THREAD_CPUTIME_ID, &spec);
	return spec.tv_nsec * 1e-9 + spec.tv_sec;	
}
time_t Timer::now() const {
	time_t res; time(&res); return res;
}
double Timer::getClockTime() {
   return clock() * (1.0 / CLOCKS_PER_SEC);
}

// this code will delete the timer object when the progam is terminated
class TimerAutoDelete {
public:
	TimerAutoDelete(){};
	virtual ~TimerAutoDelete() {
		delete Timer::instance();
	}
};
TimerAutoDelete timerAutoDelete;

#include <iostream>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include "Timer.h"
#include "Matrix.h"
#include "UnitTester.h"
#include "setThreads.h"
UNITTEST(TestTimer);
TestTimer::TestTimer() {
	setName 				("Test Timer ");
	setDescription  	("Tests timers using matrix multiplication");
	setTestAuthor		("Yordan Madzhunkov");
	setDeveloperAuthor("Yordan Madzhunkov");
	setCompileTime(__DATE__, __TIME__); // each class that inherits this one should also have this line.
};
bool TestTimer::test() const {
	const int N = 3500;
	const int nTimers = 6;
	double timings[nTimers];
	static const char * timerNames[]= {"ProcTime","UserTime","RealTime","ThreadTime", "MonoTime", "ClockTime"};

	Timer * timer = Timer::instance(); 

	Matrix A(N, N, General); A.fill(1);// A.transpose();
	Matrix B(N, N, General); B.fill(1);// B.transpose();
	
	for (int i = 1; i <= 4; i++) {
		SET_NUM_THREADS(i);

		timings[0] = timer->getProcTime();
		timings[1] = timer->getUserTime();
		timings[2] = timer->getRealTime();
		timings[3] = timer->getThreadTime();
		timings[4] = timer->getMonoTime();
		timings[5] = timer->getClockTime();
		Matrix C = A * B;
		timings[0] = timer->getProcTime()  - timings[0];
		timings[1] = timer->getUserTime()  - timings[1];
		timings[2] = timer->getRealTime()  - timings[2];
		timings[3] = timer->getThreadTime()- timings[3];
		timings[4] = timer->getMonoTime()  - timings[4];
		timings[5] = timer->getClockTime() - timings[5];

	//	cout << C.nrm2() << "\n";
		for (int i = 0; i < nTimers; i++) 
			cout << timerNames[i] << " " << timings[i] << " s" << endl;
	}

	return false;
}
//TestTimer  testTimer;
